#include "../../include/threadPool.h"
#include "../../include/myfunc.h"

int msgprocess(int netFd, train_t * train) {
    
    int ret = recvn(netFd, &train->length, sizeof(int));
    //THREAD_ERROR_CHECK(ret, "recv");
    ERROR_CHECK(ret , -1, "recv");
    
    ret = recvn(netFd, &train->buf, train->length);   
    //THREAD_ERROR_CHECK(ret, "recv");
    ERROR_CHECK(ret , -1, "recv");

    return 0;
}

int sendn(int netFd, void * buf, int len) {
    char * pbuf = (char *)buf;
    train_t train;
    bzero(&train,sizeof(train));
    train.length = len;
    strcpy(train.buf, pbuf);
    int ret = send(netFd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    ERROR_CHECK(ret, -1, "send");
    return 0;
}

int recvn(int sockFd,void *pstart,int len){
    int total = 0;
    int ret;
    char *p = (char *)pstart;
    while(total < len){
        ret = recv(sockFd,p+total,len-total,0);
        total += ret;
        if(ret == -1 || ret == 0)
            return -1;
    }
    return 0;
}

int recvFile(int netFd, char *filename)
{
    int dataLength;
    int ret = recv(netFd, &dataLength, sizeof(dataLength), 0);
    ERROR_CHECK(ret, -1, "recv");
    ret = recv(netFd, filename, dataLength, 0);
    ERROR_CHECK(ret, -1, "recv");
    int filefd = open(filename, O_RDWR | O_CREAT | O_LARGEFILE, 0666);
    ERROR_CHECK(filefd, -1, "open");
    train_t train;
    int fileSize;
    int doneSize = 0;
    int lastSize = 0;
    int slice = fileSize / 10000;

    while (1)
    {
        ret = recv(netFd, &dataLength, sizeof(int), 0);
        ERROR_CHECK(ret, -1, "recv");
        if (dataLength != 0)
        {
            printf("dataLength = %d\n", dataLength);
        }
        doneSize += dataLength;
        if (doneSize - lastSize > slice)
        {
            printf("%5.2lf%%\r", 100.0 * doneSize / fileSize);
            fflush(stdout);
            lastSize = doneSize;
        }
        if (dataLength == 0)
        {
            printf("100.00%%\n");
            break;
        }
        ret = recv(netFd, train.buf, dataLength, 0);
        ERROR_CHECK(ret, -1, "recv");
        write(filefd, train.buf, ret);
    }
}

int sendFile(int netFd, char *filename)
{

    int filefd = open(filename, O_RDWR | O_CREAT | O_LARGEFILE, 0666);

    struct stat statbuf;
    int ret = fstat(filefd, &statbuf);
    THREAD_ERROR_CHECK(ret, "fstat");
    train_t train;
    train.length = strlen(filename);
    int fileSize = statbuf.st_size;

    memcpy(train.buf, &fileSize, sizeof(int));
    strcat(train.buf, filename);
    ret = send(netFd, &train, train.length + sizeof(train.length), MSG_NOSIGNAL);
    THREAD_ERROR_CHECK(ret, "send");

    if (fileSize > 100 * 2E20)
    {
        char *p = (char *)mmap(NULL, sizeof(train.buf) + sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, filefd, 0);
        ERROR_CHECK(p, MAP_FAILED, "mmap");
        int total = 0;
        while (total < fileSize)
        {
            if (fileSize - total < sizeof(train.buf))
            {
                train.length = fileSize - total;
            }
            else
            {
                train.length = sizeof(train.buf);
            }
            memcpy(train.buf, p + total, train.length);
            total += train.length;
            ret = send(netFd, &train, train.length + sizeof(train.length), MSG_NOSIGNAL);
            ERROR_CHECK(ret, -1, "send");
        }

        munmap(p, fileSize);
    }
    else
    {
        while (1)
        {
            bzero(&train, sizeof(train));
            ret = read(filefd, train.buf, sizeof(train.buf));
            if (ret == 0)
                break;
            train.length = ret;
            ret = send(netFd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
            THREAD_ERROR_CHECK(ret, "send");
        }
    }

    train.length = 0;
    ret = send(netFd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);
    THREAD_ERROR_CHECK(ret, "send");
    close(filefd);
}
